/************************************
 * created by Tonk (tonk@ctonk.com) *
 ************************************/

// loginHandler.cpp

#ifndef LOGIN_HANDLER_CPP
#define LOGIN_HANDLER_CPP

#include "definitions.h"
#include <arpa/telnet.h>
#include "loginHandler.h"
#include "world.h"
#include "stringutil.h"
#include "logs.h"

loginHandler::loginHandler() {
	_c = 0;
	_state = CHECK_NAME;
	_flag = 0;
}

loginHandler::loginHandler( Character* c ) {
	// This constructor should, theoretically, always be used,
	// instead of the default with no parameters.
	_c = c;
	_state = CHECK_NAME;
	_flag = 0;
}

loginHandler::loginHandler( loginHandler& it ) {
	_name = it.getName();
	_output = it.getOutput();
	_c = it.getC();
	_state = it.getState();
	_flag = it.getFlag();
}

loginHandler::~loginHandler() { }

loginHandler& loginHandler::operator = ( loginHandler& it ) {
	_name = it.getName();
	_output = it.getOutput();
	_c = it.getC();
	_state = it.getState();
	_flag = it.getFlag();
	return *this;
}

std::string& loginHandler::getName() {
	return this->_name;
}

std::string& loginHandler::getOutput() {
	return this->_output;
}

Character* loginHandler::getC() {
	return this->_c;
}

int loginHandler::getState() {
	return this->_state;
}

int loginHandler::getFlag() {
	return this->_flag;
}

std::list< loginHandler* >& loginList::getLogins() {
	return this->_logins;
}

bool loginHandler::checkName( Character* c, const string& args ) {
	std::string name = args;

	ltrim( name, name );
	rtrim( name, name );
	loginTrim( name, name );
	c->setName( name );

	// Check for existence of pfile.
	if ( c->cLoad() == -1 ) {
		// pfile doesn't exist, or was corrupt. Disconnect the user.
		c->SetDisconnected( true );
		return true;
	} else {
		// pfile exists, and load was successful. Move on to ask for a password.
		//static const char echo_off[] = {IAC, WILL, TELOPT_ECHO, '\0'};
		c->Send( "password: " );
		_state++;
	}

	return false;
}

bool loginHandler::checkPassword( Character* c, const string& args ) {
	std::string buf;
	std::string password = args;
	rtrim( password, password );

	// Check password.
	if ( c->GetPword() != password ) {
		// Password was incorrect. Disconnect user.
		c->SetDisconnected( true );
		return true;
	} else {
		// Password was correct. Update status and send a welcome message.
		//static const char echo_off[] = {IAC, WILL, TELOPT_ECHO, '\0'};
		c->Send( "Welcome!\n\r\n\r" );
		c->SetStatus( CONNECTED );
		log( c->getName(), c->getLevel(), "logged in" );
		buf << c->getName() << " has connected.";
		World::Instance().Omninet( buf, STANDARD, NULL, false );
		_state++;
		return true;
	}

	return true;
}

bool loginHandler::fire( Character* c, const string& args ) {
	// loginHandler::fire() evaluates input for a login and responds
	// accordingly. Returns true when the handler object needs to be
	// destroyed and removed from the list.
	bool destroy = false;
	std::string input = args;
	rtrim( input, input );

	switch( this->_state ) {
		case CHECK_NAME:
			// args should contain the name of the player.
			destroy = checkName( c, input );
			break;
		case CHECK_PASSWORD:
			// args should contain a password attempt.
			destroy = checkPassword( c, input );
			break;
		default:
			// Something funky happened with the loginHandler::_state variable.
			c->Send( "error\n\r\n\r" );
			destroy = true;
			c->SetDisconnected( true );
			break;
	}

	return destroy;
}

void loginList::act( Character* c, const string& args ) {
	// If c is new to the loginList, a new loginHandler is created.
	// Otherwise, the correct loginHandler is called.
	// Then loginHandler::fire() is executed.
	loginHandler* lh = 0;
	bool newLogin = true;

	for ( std::list< loginHandler* >::iterator it = _logins.begin(); it != _logins.end(); it++ ) {
		// Find out if this Character needs a new loginHandler.
		if ( (*it)->getC()->getName() == c->getName() ) {
			// This Character has a loginHandler already.
			newLogin = false;
			lh = (*it);
			break;
		}
	}

	if ( newLogin ) {
		// Create a new loginHandler in the list.
		Instance().getLogins().push_back( new loginHandler( c ) );
		lh = Instance().getLogins().back();
	}

	// loginHandler::fire() does the main work.
	// Also, it returns true if it's done it's job,
	// and needs to be ousted from the list.
	if ( lh->fire( c, args ) ) {
		// remove lh from the list
		delete lh;
		Instance().getLogins().remove( lh );
	}

	return;
}


#endif // #ifndef LOGIN_HANDLER_CPP
